package com.uzhie.media;

import com.alibaba.fastjson.JSON;
import com.uzhie.media.bean.MediaMsgBean;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
import org.apache.log4j.Logger;

/**
 * Created by TangFei on 2018/7/25.
 * 多媒体协议请求处理
 */
@ChannelHandler.Sharable
public class MediaChannelInHandler extends ChannelInboundHandlerAdapter {

    private Logger logger = Logger.getLogger(this.getClass());
    private MediaDispatcher mediaDispatcher;
    // 当前线程接收到的消息
    private MediaMsgBean currentReqMsg;
    // 当前线程返回消息
    private MediaMsgBean currentResMsg;

    public void setMediaDispatcher(MediaDispatcher mediaDispatcher) {
        this.mediaDispatcher = mediaDispatcher;
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        logger.trace(String.format("enter method %s", Thread.currentThread().getStackTrace()[1].getMethodName()));
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        logger.trace(String.format("enter method %s", Thread.currentThread().getStackTrace()[1].getMethodName()));
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        MediaChannelHandlerContextHolder.setContextThreadLocal(ctx);
        logger.trace(String.format("enter method %s", Thread.currentThread().getStackTrace()[1].getMethodName()));
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        MediaChannelHandlerContextHolder.removeContextThreadLocal();
        logger.trace(String.format("enter method %s", Thread.currentThread().getStackTrace()[1].getMethodName()));
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.trace(String.format("enter method %s", Thread.currentThread().getStackTrace()[1].getMethodName()));
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.trace(String.format("enter method %s", Thread.currentThread().getStackTrace()[1].getMethodName()));
    }

    /**
     * 这个方法在解码器执行add之后 就会触发
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        logger.trace(String.format("enter method %s", Thread.currentThread().getStackTrace()[1].getMethodName()));
        if (msg instanceof MediaMsgBean) {
            MediaChannelHandlerContextHolder.setContextThreadLocal(ctx);
            currentReqMsg = (MediaMsgBean) msg;
            // 消息分发
            currentResMsg = mediaDispatcher.dispatch(currentReqMsg);
        } else {
            logger.error("平台收到流媒体消息异常！");
            throw new ClassCastException("平台收到流媒体消息异常");
        }
        ReferenceCountUtil.release(msg);
        if (null != currentResMsg.getMsgBody()) {
            ctx.writeAndFlush(currentResMsg);
        }
    }

    /**
     * 这个方法是在通道读取完流数据之后才会触发
     * 如果存在粘包情况 那么这个方法会在所有粘包处理完成之后 才会触发 就会导致在粘包情况下 只会回复一次
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        logger.trace(String.format("enter method %s", Thread.currentThread().getStackTrace()[1].getMethodName()));
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        logger.trace(String.format("enter method %s", Thread.currentThread().getStackTrace()[1].getMethodName()));
    }

    /**
     * 异常发生时触发
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.trace(String.format("enter method %s", Thread.currentThread().getStackTrace()[1].getMethodName()));
        logger.error("消息ID：" + currentReqMsg.getHexMsgID() + " 发生异常 " + cause.getCause() + " 位置：" + cause.getCause().getStackTrace()[0].toString());
        currentResMsg = currentReqMsg;
        currentResMsg.setMsgBody(JSON.parseObject("{\"code\":500,\"msg\":\"ERROR\",\"result\":{\"data\":\"null\"}}"));
        ctx.writeAndFlush(currentResMsg);
    }
}
